import { CoroutineLockComponent } from "../../../../../Core/Module/CoroutineLock/CoroutineLockComponent";
import { CoroutineLockType } from "../../../../../Core/Module/CoroutineLock/CoroutineLockType";
import { Root } from "../../../../../Core/Module/Entity/Root";
import { InstanceIdStruct } from "../../../../../Core/Module/IdGenerater/IdGenerater";
import { Log } from "../../../../../Core/Module/Log/Log";
import { ErrorCore } from "../../../../../Core/Module/Network/ErrorCore";
import { Options } from "../../../../../Core/Module/Options/Options";
import { Exception } from "../../../../../Core/Object/Exception";
import { GetTypeOf } from "../../../../../Decorator/Decorator";
import { ActorMessageDispatcherComponent } from "../../../../Model/Server/Module/Actor/ActorMessageDispatcherComponent";
import { ActorMessageSenderComponent } from "../../../../Model/Server/Module/Actor/ActorMessageSenderComponent";
import { MailBoxComponent } from "../../../../Model/Server/Module/Actor/MailBoxComponent";
import { MailboxType } from "../../../../Model/Server/Module/Actor/MailboxType";
import { NetInnerComponent } from "../../../../Model/Server/Module/Message/NetInnerComponent";
import { IActorMessage, IActorRequest, IActorResponse } from "../../../../Model/Share/Module/Actor/IActorMessage";
import { Session } from "../../../../Model/Share/Module/Message/Session";
import { ActorHelper } from "./ActorHelper";

export class ActorHandleHelper {

    public static async Reply(fromProcess: number, response: IActorResponse): Promise<void> {
        // console.log(`ActorHandleHelper.Reply`);
        // console.log(fromProcess);
        // console.log(response);

        if (fromProcess == Options.Instance.Process) // 返回消息是同一个进程
        {
            // NetInnerComponent.Instance.HandleMessage(realActorId, response); 等同于直接调用下面这句
            ActorMessageSenderComponent.Instance.HandleIActorResponse(response);
            return;
        }
        let replySession = await NetInnerComponent.Instance.Get(fromProcess);
        replySession.Send(response);
    }

    public static HandleIActorResponse(response: IActorResponse): void {
        // console.log(`ActorHandleHelper.HandleIActorResponse`);
        // console.log(response);

        ActorMessageSenderComponent.Instance.HandleIActorResponse(response);
    }

    /// <summary>
    /// 分发actor消息
    /// </summary>
    public static async HandleIActorRequest(actorId: number, iActorRequest: IActorRequest): Promise<void> {
        // console.log(`ActorHandleHelper.HandleIActorRequest`);
        // console.log(actorId);
        // console.log(iActorRequest);

        let instanceIdStruct = InstanceIdStruct.Create(actorId);
        let fromProcess = instanceIdStruct.Process;
        instanceIdStruct.Process = Options.Instance.Process;
        let realActorId = instanceIdStruct.ToLong();

        let entity = Root.Instance.Get(realActorId);
        if (entity == null) {
            let response = ActorHelper.CreateResponse(iActorRequest, ErrorCore.ERR_NotFoundActor);
            this.Reply(fromProcess, response);
            return;
        }
        let mailBoxComponent = entity.GetComponent<MailBoxComponent>(MailBoxComponent);
        if (mailBoxComponent == null) {
            Log.Warning(`actor not found mailbox: ${GetTypeOf(entity)} ${realActorId} ${iActorRequest}`);
            let response = ActorHelper.CreateResponse(iActorRequest, ErrorCore.ERR_NotFoundActor);
            this.Reply(fromProcess, response);
            return;
        }

        switch (mailBoxComponent.MailboxType) {
            case MailboxType.MessageDispatcher:
                {
                    let coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Mailbox, realActorId);
                    if (entity.InstanceId != realActorId) {
                        let response = ActorHelper.CreateResponse(iActorRequest, ErrorCore.ERR_NotFoundActor);
                        this.Reply(fromProcess, response);
                        coroutineLock.Dispose();
                        break;
                    }
                    await ActorMessageDispatcherComponent.Instance.Handle(entity, fromProcess, iActorRequest);
                    coroutineLock.Dispose();
                    break;
                }
            case MailboxType.UnOrderMessageDispatcher:
                {
                    await ActorMessageDispatcherComponent.Instance.Handle(entity, fromProcess, iActorRequest);
                    break;
                }
            case MailboxType.GateSession:
            default:
                throw new Exception(`no mailboxtype: ${mailBoxComponent.MailboxType} ${iActorRequest}`);
        }
    }

    /// <summary>
    /// 分发actor消息
    /// </summary>
    public static async HandleIActorMessage(actorId: number, iActorMessage: IActorMessage): Promise<void> {
        // console.log(`ActorHandleHelper.HandleIActorMessage`);
        // console.log(actorId);
        // console.log(iActorMessage);

        let instanceIdStruct = InstanceIdStruct.Create(actorId);
        let fromProcess = instanceIdStruct.Process;
        instanceIdStruct.Process = Options.Instance.Process;
        let realActorId = instanceIdStruct.ToLong();

        let entity = Root.Instance.Get(realActorId);
        if (entity == null) {
            Log.Error(`not found actor: ${realActorId} ${iActorMessage}`);
            return;
        }

        let mailBoxComponent = entity.GetComponent<MailBoxComponent>(MailBoxComponent);
        if (mailBoxComponent == null) {
            Log.Error(`actor not found mailbox: ${GetTypeOf(entity)} ${realActorId} ${iActorMessage}`);
            return;
        }

        switch (mailBoxComponent.MailboxType) {
            case MailboxType.MessageDispatcher:
                {
                    let coroutineLock = await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Mailbox, realActorId);
                    if (entity.InstanceId != realActorId) {
                        coroutineLock.Dispose();
                        break;
                    }
                    await ActorMessageDispatcherComponent.Instance.Handle(entity, fromProcess, iActorMessage);
                    coroutineLock.Dispose();
                    break;
                }
            case MailboxType.UnOrderMessageDispatcher:
                {
                    await ActorMessageDispatcherComponent.Instance.Handle(entity, fromProcess, iActorMessage);
                    break;
                }
            case MailboxType.GateSession:
                {
                    if (entity instanceof Session) {
                        let gateSession = entity as Session;
                        gateSession.Send(iActorMessage);
                    }
                    break;
                }
            default:
                throw new Exception(`no mailboxtype: ${mailBoxComponent.MailboxType} ${iActorMessage}`);
        }
    }

}